#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@IDE     ：PyCharm 
@Author  ：kiway
@Date    ：2024/7/26 14:13 
"""

from collections import defaultdict
from typing import Callable, Dict, Optional
from ..tools import load_json
from .BaseEngine import (EVENT_TRADE, EVENT_PrORDER,
                         TradeEvent, PrOrderEvent,
                         BaseEngine, PsOrderEvent,
                         EVENT_POSITIONS_UPDATE, EVENT_BALANCE_UPDATE)

from ..logger import pretty_print
import traceback
import multiprocessing
import asyncio

# from vnpy.event import Event, EventEngine
# from vnpy.trader.object import OrderData, OrderRequest, LogData, TradeData
# from vnpy.trader.engine import BaseEngine, MainEngine
# from vnpy.trader.event import EVENT_TRADE, EVENT_ORDER, EVENT_LOG, EVENT_TIMER
# from vnpy.trader.constant import Direction, Status
# from vnpy.trader.utility import load_json, save_json


APP_NAME = "RiskManager"


class RiskEngine(BaseEngine):
    """风控引擎"""

    def __init__(self, main_engine) -> None:
        """"""
        super().__init__("风控引擎", main_engine)
        self.active: bool = False
        self.balance_info_df = None
        self.position_info_df = None
        self.order_flow_count: int = 0
        self.order_flow_limit: int = 50

        self.order_flow_clear: int = 1
        self.order_flow_timer: int = 0

        self.order_size_limit: int = 100

        self.trade_count: int = 0
        self.trade_limit: int = 1000

        self.order_cancel_limit: int = 500
        self.order_cancel_counts: Dict[str, int] = defaultdict(int)

        self.active_order_limit: int = 50

        self.load_setting()

    def update_setting(self, setting: dict) -> None:
        """"""
        self.active = setting["active"]
        self.order_flow_limit = setting["order_flow_limit"]
        self.order_flow_clear = setting["order_flow_clear"]
        self.order_size_limit = setting["order_size_limit"]
        self.trade_limit = setting["trade_limit"]
        self.active_order_limit = setting["active_order_limit"]
        self.order_cancel_limit = setting["order_cancel_limit"]

    def get_setting(self) -> dict:
        """"""
        setting: dict = {
            "active": self.active,
            "order_flow_limit": self.order_flow_limit,
            "order_flow_clear": self.order_flow_clear,
            "order_size_limit": self.order_size_limit,
            "trade_limit": self.trade_limit,
            "active_order_limit": self.active_order_limit,
            "order_cancel_limit": self.order_cancel_limit,
        }
        return setting

    async def on_event(self):
        while True:
            try:
                event = self._msg_q.get()
                if event.type == EVENT_PrORDER:
                    await self.process_order_event(event)

                # elif event.type == EVENT_BALANCE_UPDATE:
                #     self.balance_info_df = event.data
                #
                # elif event.type == EVENT_POSITIONS_UPDATE:
                #     self.position_info_df = event.data


            except:
                traceback.print_exc()

    def load_setting(self) -> None:
        """"""
        setting: dict = load_json("Config/risk_manager.json")
        if not setting:
            return

        self.update_setting(setting)

    async def process_order_event(self, event: PrOrderEvent) -> None:
        """"""
        # trade = event.data
        # self.trade_count += trade.volume
        # self.check_risk(event.data)

        self.main_engine.put_event(PsOrderEvent(event.symbol, event.data, event.exchange_id))

    def check_risk(self, req) -> bool:
        """"""

        # Check order volume
        if req.volume <= 0:
            pretty_print("委托数量必须大于0")
            return False

        if req.volume > self.order_size_limit:
            pretty_print(
                f"单笔委托数量{req.volume}，超过限制{self.order_size_limit}")
            return False

        # Check trade volume
        if self.trade_count >= self.trade_limit:
            pretty_print(
                f"今日总成交合约数量{self.trade_count}，超过限制{self.trade_limit}")
            return False

        # Check flow count
        if self.order_flow_count >= self.order_flow_limit:
            pretty_print(
                f"委托流数量{self.order_flow_count}，超过限制每{self.order_flow_clear}秒{self.order_flow_limit}次")
            return False

        # Check all active orders
        active_order_count: int = len(self.main_engine.get_all_active_orders())
        if active_order_count >= self.active_order_limit:
            pretty_print(
                f"当前活动委托次数{active_order_count}，超过限制{self.active_order_limit}")
            return False

        # Check order cancel counts
        order_cancel_count: int = self.order_cancel_counts.get(req.vt_symbol, 0)
        if order_cancel_count >= self.order_cancel_limit:
            pretty_print(f"当日{req.vt_symbol}撤单次数{order_cancel_count}，超过限制{self.order_cancel_limit}")
            return False

        # # Add flow count if pass all checks
        self.order_flow_count += 1
        return True

    def _start(self):
        p = multiprocessing.Process(target=self._run)
        p.start()

    def _run(self):
        loop = asyncio.new_event_loop()
        loop.create_task(self.on_event())
        loop.run_forever()
